package vno.fux.res.manager
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	
	import vno.fux.utils.IMissionDispatcher;

	public class LoaderManager extends EventDispatcher implements IMissionDispatcher
	{
		private static var instance:LoaderManager;
		
		private const obj_id:String = "RM_LM";
		private var _loaders:Array;
		private var _loadQueue:Array;
		private var _freeLoaders:Array;
		private var _loaderNum:int;
		private var _missionId:uint = 0;
		
		public function LoaderManager(loaderNum_:int = 4)
		{
			if(loaderNum_<=0)
			{
				throw new Error("Number of loader should >0");
			}
			_loaderNum = loaderNum_;
			_loaders = new Array(_loaderNum);
			_freeLoaders = [];
			_loadQueue = [];
			for(var i:int=0; i<_loaderNum; i++)
			{
				_freeLoaders[i] = _loaders[i] = new CommonLoader(i);
			}
		}
		
		public function addMission(mission:ResourceMission):void
		{
			var loader:CommonLoader = _freeLoaders.pop();
 			if(loader)
			{
				loader.addEventListener(Event.COMPLETE, completeHandler);
				loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
				loader.addEventListener(ProgressEvent.PROGRESS, progressHandler);
				if(mission.host) mission.host.setLoadState(new LoadState(mission.target, LoadState.LOADING));
				loader.load(mission);
			} 
			else
			{
				_loadQueue.push(mission);
				if(mission.host) mission.host.setLoadState(new LoadState(mission.target, LoadState.IN_QUEUE));
			}
		}
		
		protected function progressHandler(event:ProgressEvent):void
		{
			var loader:CommonLoader = event.target as CommonLoader;
			var evtStr:String =ProgressEvent.PROGRESS+obj_id+loader.missionId;
			dispatchEvent(new ProgressEvent(evtStr,false,false,event.bytesLoaded,event.bytesTotal));
		}
		
		protected function completeHandler(event:Event):void
		{
			var loader:CommonLoader = event.target as CommonLoader;
			var evtStr:String = Event.COMPLETE+obj_id+loader.missionId;
			dispatchEvent(new Event(evtStr));
			var mission:ResourceMission = _loadQueue.shift();
			if(mission)
			{
				if(mission.host) mission.host.setLoadState(new LoadState(mission.target, LoadState.LOADING));
				loader.load(mission);
			}
			else
			{
				loader.removeEventListener(Event.COMPLETE, completeHandler);
				loader.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
				loader.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
				_freeLoaders.push(loader);
			}
		}
		
		protected function errorHandler(event:Event):void
		{
			var loader:CommonLoader = event.target as CommonLoader;
			var errorMission:ResourceMission = loader.currentMission;
			if(errorMission.host) errorMission.host.setLoadState(new LoadState(errorMission.target, LoadState.NOT_LOAD));
			var mission:ResourceMission;
			if(errorMission.retry>0)
			{
				errorMission.retry = errorMission.retry-1;
				mission = errorMission;
				trace("Try to reload", mission);
			}
			else
			{
				mission = _loadQueue.shift();
			}
			if(mission)
			{
				if(mission.host) mission.host.setLoadState(new LoadState(mission.target, LoadState.LOADING));
				loader.load(mission);
			}
			else
			{
				loader.removeEventListener(Event.COMPLETE, completeHandler);
				loader.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
				_freeLoaders.push(loader); 
			}
		}
		
		public function getId():uint
		{
			return _missionId++;
		}

		public function getCurrentMissionCompleteEvent():String
		{
			return Event.COMPLETE+obj_id+_missionId;
		}
		public function getCurrentMissionProgressEvent():String
		{
			return ProgressEvent.PROGRESS+obj_id+_missionId;
		}
	}
}
